#include "main.h"
#include "gpio.h"
#include "i2c.h"
#include <string.h>
#include "tim.h"

uint8_t CC_Line = 0;

static uint8_t read_buff[64] = { 0 };
static uint8_t write_buff[64] = { 0 };

volatile uint8_t Pdo_Number = 0;
uint8_t Pdo_Buff[8][4] = { 0 };

volatile uint8_t PPS_Index = 0; // PPS Flag
volatile uint16_t PPS_Volt = 0;
volatile uint16_t PPS_Curr = 0;
volatile uint32_t PPS_Timer_Count = 0;

volatile uint8_t Msg_ID = 0;

const uint8_t Request_Tpl[14] = 
{ 
	0x12, 0x12, 0x12, 0x13, 0x86,
	0x82, 0x10,
	0x00, 0x00, 0x00, 0x03,
	0xff, 0x14, 0xA1
};

uint8_t Request_buff[14] = { 0 }; 

uint8_t FUSB_Read_Reg(uint8_t addr)
{
	uint8_t data = 0;
	HAL_I2C_Mem_Read(&hi2c3, 0x45, addr, I2C_MEMADD_SIZE_8BIT, &data, 1, 0xFF);
	return data;
}

uint8_t FUSB_Read_Fifo(uint8_t *buff, uint8_t len)
{
	return HAL_I2C_Mem_Read(&hi2c3, 0x45, 0x43, I2C_MEMADD_SIZE_8BIT, buff, len, 0xFF);
}

uint8_t FUSB_Write_Reg(uint8_t addr, uint8_t data)
{
	return HAL_I2C_Mem_Write(&hi2c3, 0x44, addr, I2C_MEMADD_SIZE_8BIT, &data, 1, 0xFF);
}

uint8_t FUSB_Write_Fifo(uint8_t *buff, uint8_t len)
{
	return HAL_I2C_Mem_Write(&hi2c3, 0x44, 0x43, I2C_MEMADD_SIZE_8BIT, buff, len, 0xFF);
}

uint8_t FUSB_Check_CC(void)
{
	uint8_t r40 = 0, t = 0;
	FUSB_Write_Reg(0x0B, 0x0F); 
	FUSB_Write_Reg(0x02, 0x07); 
	HAL_Delay(10);
	t = 10;
	while(t --)
	{
		r40 = FUSB_Read_Reg(0x40);
		if((r40 & 0x03) > 0)	return 1;
		HAL_Delay(10);
	}
	FUSB_Write_Reg(0x02, 0x0B); 
	HAL_Delay(10);
	t = 10;
	while(t --)
	{
		r40 = FUSB_Read_Reg(0x40);
		if((r40 & 0x03) > 0)	return 2;
		HAL_Delay(10);
	}
	return 0;
}

uint8_t FUSB_Init(uint8_t time)
{
	if(FUSB_Write_Reg(0x02, 0x00) != HAL_OK) // Disable Rd 
	{
		return 1;
	}
	
	Pdo_Number = 0;
	Msg_ID = 0;
	
	HAL_Delay(time * 10);  
	FUSB_Write_Reg(0x0C, 0x03);
	CC_Line = FUSB_Check_CC();
	
	if(CC_Line == 0)
	{
		return 2;
	}
	
	FUSB_Write_Reg(0x09, 0x40);
	FUSB_Write_Reg(0x0C, 0x03);
	HAL_Delay(5);  
	FUSB_Write_Reg(0x09, 0x07);
	FUSB_Write_Reg(0x0E, 0xFC);
	FUSB_Write_Reg(0x0F, 0x01);
	FUSB_Write_Reg(0x0A, 0xEF);
	FUSB_Write_Reg(0x06, 0x00);
	FUSB_Write_Reg(0x0C, 0x02);
	
	if (CC_Line == 1)
	{
			FUSB_Write_Reg(0x02, 0x07); 
			FUSB_Write_Reg(0x03, 0x45); 
	}
	else if (CC_Line == 2)
	{
			FUSB_Write_Reg(0x02, 0x0B);
			FUSB_Write_Reg(0x03, 0x46);
	}
	
	FUSB_Write_Reg(0x0B, 0x0F); 
	FUSB_Read_Reg(0x3E);
  FUSB_Read_Reg(0x3F);
  FUSB_Read_Reg(0x42);
	return 0;
}

void FUSB_Rd_Control(uint8_t state)
{
	FUSB_Write_Reg(0x02, state & 0x03);
}

void FUSB_Request(uint8_t pdo_idx, uint16_t volt, uint16_t curr)
{
	if((pdo_idx == 0) || (pdo_idx > Pdo_Number)) return;
	
	PPS_Index = 0;
	PPS_Timer_Count = 0;
	
	memcpy(Request_buff, Request_Tpl, 14);
	
	if((Pdo_Buff[pdo_idx - 1][3] & 0xC0) == 0) // Fixed
	{
		if(curr == 0)
		{
			curr = Pdo_Buff[pdo_idx - 1][1] & 0x03;
			curr <<= 8;
			curr |= Pdo_Buff[pdo_idx - 1][0];
		}
		else
		{
			curr = curr / 10; //Operating current in 10mA units
		}
		Request_buff[10] |=  pdo_idx << 4;
		Request_buff[9] = curr >> 6;
		Request_buff[8] = curr << 2;
		Request_buff[8]|= Pdo_Buff[pdo_idx - 1][1] & 0x03;
		Request_buff[7] = Pdo_Buff[pdo_idx - 1][0];
	}
	else // PPS
	{
		if(volt == 0)
		{
			volt = Pdo_Buff[pdo_idx - 1][2] >> 1;
			volt|= (Pdo_Buff[pdo_idx - 1][3]&0x01) << 7;
			volt *= 5;
		}
		else
		{
			volt = volt / 20; // Output Voltage in 20mV units.
		}

		if(curr == 0)
		{
			curr = Pdo_Buff[pdo_idx - 1][0];
		}
		else
		{
			curr = curr / 50; //Operating Current 50mA units
		}
		
		PPS_Index = pdo_idx;
		PPS_Volt = volt * 20;
		PPS_Curr = curr * 50;
		
		Request_buff[10] |=  pdo_idx << 4;
		Request_buff[9] = volt >> 7;
		Request_buff[8] = volt << 1;
		Request_buff[7] = curr & 0x7F;
	}
	Request_buff[6] |= Msg_ID << 1;
	FUSB_Write_Fifo(Request_buff, 14);
	Msg_ID ++;
	Msg_ID &= 0x07;
}

char PD_Set_Volt(uint16_t volt) // mV
{
	uint16_t pdo_volt = 0;
	for(int i = 0; i < Pdo_Number; i ++)
	{
		if((Pdo_Buff[i][3] & 0xC0) == 0) // Fixed
		{
			pdo_volt = Pdo_Buff[i][1] >> 2; 
			pdo_volt|= (Pdo_Buff[i][2]  & 0x0F) << 6; 
			pdo_volt *= 50;
			if(pdo_volt == volt)
			{
				FUSB_Request(i + 1, 0, 0);
				return 0;
			}
		}
		else // pps
		{
			pdo_volt = Pdo_Buff[i][1] * 100; // min Volt
			if(volt < pdo_volt) continue;
			
			pdo_volt = Pdo_Buff[i][2] >> 1;
			pdo_volt|= (Pdo_Buff[i][3] & 0x01) << 7;
			pdo_volt*= 100; //max Volt
			if(volt > pdo_volt) continue;
			
			FUSB_Request(i + 1, volt, 0);
			return 0;
		}
	}
	return 1;
}

void FUSB_Read_SourceCap(uint8_t Nunber)
{
	FUSB_Read_Fifo(Pdo_Buff[0], Nunber*4);
	Pdo_Number = Nunber;
	HAL_Delay_ms(2);
	FUSB_Request(1,0, 0);
}

void PPS_Timer_Handler(void)
{
	if(PPS_Index == 0) return;
	PPS_Timer_Count ++;
	
	if(PPS_Timer_Count == 10000) // 10000 mS = 10S
	{
		PPS_Timer_Count = 0;
		FUSB_Request(PPS_Index, PPS_Volt, PPS_Curr);
	}
}

void FUSB_IRQHandler(void)
{
	HAL_I2C_Mem_Read(&hi2c3, 0x45, 0x42, I2C_MEMADD_SIZE_8BIT, read_buff, 4, 0xFF);
	
	if((read_buff[1] & 0xe0 ) == 0)
	{
		FUSB_Write_Reg(0x07, 0x04);
		return;
	}

	if((read_buff[3] & 0x70) > 0) // Data Msg
	{
		switch(read_buff[2] & 0x1F)
		{
			case 0x01: // SourceCap
				FUSB_Read_SourceCap((read_buff[3] & 0x70) >> 4);
				break;
			case 0x0F: // Vendor Defined Message
				break;
		}
	}
	else // Control Msg
	{
		switch(read_buff[2] & 0x1F)
		{
			case 0x03: // Accept
				break;
			case 0x04: // Reject
				break;
			case 0x06: // PS_RDY
				break;
			case 0x0D: // Soft_Reset
				break;
		}
	}
	FUSB_Write_Reg(0x07, 0x04); // Clean the Rx_Buff of chip
}
